home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 7
/
Apprentice-Release7.iso
/
Source Code
/
Pascal
/
Games
/
C-Pong
/
c-pong.p
next >
Wrap
Text File
|
1997-01-15
|
17KB
|
729 lines
program pong;
uses
{$IFC UNDEFINED THINK_PASCAL}
Types, QuickDraw, Events, Windows, Dialogs, Fonts, DiskInit, TextEdit, Traps,{}
Memory, SegLoad, Scrap, ToolUtils, OSUtils, Menus, Resources, StandardFile,{}
GestaltEqu, Files, Errors, Devices, QuickDrawText, TextUtils,{}
{$ENDC}
Sound;
(* pong.c}
{ The classic game of pong in Megamax C for the Mac.}
{ Thanks to MacTutor (Vol 1, No. 5 April 1985 page 39) for }
{ animation techniques. If you are reading this and don't }
{ subscribe to MacTutor, consider it. No resource file is }
{ needed. This program, source and object, is in the}
{ public domain and not for sale. }
{ }
{ Author : David L. O'Connor, 370 Eden St. Buffalo, N.Y. }
{ 14220. (716) 828-0898. CIS - 70265,1172 }
{ Date : July, 1985 Version 2}
{ }
{ }
{ Changes by Ingemar 1996:}
{ - Speed limit}
{ - Keyboard equivalents}
{ - Modern #includes}
{ - GetOSEvent makes it acceptably fast}
{*)
(* the game diRections *)
const
STOPPED = 0;
UP = 1;
DOWN = 2;
LEFT = 3;
RIGHT = 4;
UP_LEFT = 5;
UP_RIGHT = 6;
DOWN_LEFT = 7;
DOWN_RIGHT = 8;
(* paddle + ball dimensions *)
PADWIDTH = 10;
PADLENGTH = 45;
PADINSET = 10;
BALLWIDTH = 9;
BALLLENGTH = 9;
BALLSPEED = 7;
PADDLESPEED = 9;
HIGHSCORE = 21;
(* the menu ids *)
appleid = 128;
fileid = 129;
editid = 130;
skillid = 131;
soundid = 132;
(* from the MAC's standard pattern list *)
{PAD_PAT= ((*pat_Handle)->pat_list[6]);}
{WALL_PAT= ((*pat_Handle)->pat_list[10]);}
var
PAD_PAT: Pattern;
WALL_PAT: Pattern;
type
sys_patterns = record
pat_cnt: Integer;
pat_list: array[0..37] of Pattern;
end;
SysPatternPtr = ^sys_patterns;
SysPatternHnd = ^SysPatternPtr;
type
paddle = record
r: Rect;
dir: Integer;
speed: Integer;
score: Integer;
end;
type
target = record
Rgn: RgnHandle;
oldRgn: RgnHandle;
unRgn: RgnHandle;
dir: Integer;
speed: Integer;
on: Boolean;
end;
type
bleep_tag = record
mode: Integer;
triplet: array[0..0] of Tone;
end;
type
blat_tag = record
mode: Integer;
triplet: array[0..1] of Tone;
end;
var
bleep_buf: bleep_tag;
blat_buf: blat_tag;
l_paddle, r_paddle: paddle;
ball: target;
pat_Handle: SysPatternHnd;
gamewindow, which_window: WindowPtr;
winstorage: WindowRecord;
r, dragRect, top_wall, bottom_wall: Rect;
gameEvent: EventRecord;
gamemenu: array[0..4] of MenuHandle;
menutitle: array[0..0] of char;
skill_level, last_won, volleys: Integer;
done, paused, sound_on: Boolean;
const
kTitle = ' Left 00 MAC_Pong Right 00 ';
var
title: Str255;
(* Every so often, let the Mac's paddle fail to track the ball until}
{ the ball has passed it by a certain amount.}
{ This is the heart of a satisfying game. *)
function handicap: Integer;
var
mac_skill: Integer;
begin
case skill_level of
1:
mac_skill := 2;
2:
mac_skill := 8;
3:
mac_skill := 27;
4:
mac_skill := 64;
otherwise
mac_skill := 2;
end; {case}
if Random mod mac_skill = 0 then
handicap := 5
else
handicap := 0;
end;
procedure blat;
begin
if (sound_on) then
begin
if (not SoundDone) then
StopSound;
StartSound(Ptr(@blat_buf), sizeof(blat_buf), nil);
end;
end;
procedure bleep;
begin
if (sound_on) then
begin
if (not SoundDone) then
StopSound;
StartSound(Ptr(@bleep_buf), sizeof(bleep_buf), nil);
end;
end;
procedure display_score;
var
i: LongInt;
begin
i := l_paddle.score;
title[15] := Char($30 + (i div 100));
title[16] := Char($30 + ((i mod 100) div 10));
title[17] := Char($30 + (i mod 10));
i := r_paddle.score;
title[63] := Char($30 + (i div 100));
title[64] := Char($30 + ((i mod 100) div 10));
title[65] := Char($30 + (i mod 10));
SetWTitle(gamewindow, title);
end;
(* the ball eats the walls and paddles *)
procedure recover_from_collision;
var
rp: Rect;
begin
rp := ball.unRgn^^.rgnBBox;
if (SectRect(rp, top_wall, r)) then
FillRect(r, WALL_PAT)
else if (SectRect(rp, bottom_wall, r)) then
FillRect(r, WALL_PAT);
if (SectRect(rp, l_paddle.r, r)) then
FillRect(r, PAD_PAT)
else if (SectRect(rp, r_paddle.r, r)) then
FillRect(r, PAD_PAT);
end;
procedure move_ball;
begin
if (ball.on) then
begin
CopyRgn(ball.Rgn, ball.oldRgn);
case ball.dir of
LEFT:
OffsetRgn(ball.Rgn, -ball.speed, 0);
RIGHT:
OffsetRgn(ball.Rgn, ball.speed, 0);
UP_LEFT:
OffsetRgn(ball.Rgn, -ball.speed, -ball.speed);
UP_RIGHT:
OffsetRgn(ball.Rgn, ball.speed, -ball.speed);
DOWN_LEFT:
OffsetRgn(ball.Rgn, -ball.speed, ball.speed);
DOWN_RIGHT:
OffsetRgn(ball.Rgn, ball.speed, ball.speed);
end; {case}
UnionRgn(ball.Rgn, ball.oldRgn, ball.unRgn);
DiffRgn(ball.unRgn, ball.Rgn, ball.unRgn);
EraseRgn(ball.unRgn);
PaintRgn(ball.Rgn);
recover_from_collision;
end;
end;
procedure move_right_paddle;
begin
if (r_paddle.dir = STOPPED) then
FillRect(r_paddle.r, PAD_PAT)
else
begin
r.left := r_paddle.r.left;
r.right := r_paddle.r.right;
case r_paddle.dir of
UP:
begin
r.bottom := r_paddle.r.bottom;
r_paddle.r.top := r_paddle.r.top - r_paddle.speed;
r_paddle.r.bottom := r_paddle.r.bottom - r_paddle.speed;
r.top := r_paddle.r.bottom;
end;
DOWN:
begin
r.top := r_paddle.r.top;
r_paddle.r.top := r_paddle.r.top + r_paddle.speed;
r_paddle.r.bottom := r_paddle.r.bottom + r_paddle.speed;
r.bottom := r_paddle.r.top;
end;
end;
EraseRect(r);
FillRect(r_paddle.r, PAD_PAT);
end;
end;
procedure move_left_paddle;
var
mouseloc: Point;
newtop, newbottom: Integer;
begin
GetMouse(mouseloc);
if (mouseloc.v <> l_paddle.r.top) then
begin
r.left := l_paddle.r.left;
r.right := l_paddle.r.right;
if (mouseloc.v <= winstorage.port.portRect.top) then
begin
newtop := winstorage.port.portRect.top;
newbottom := newtop + PADLENGTH;
end
else if (mouseloc.v + PADLENGTH >= winstorage.port.portRect.bottom) then
begin
newbottom := winstorage.port.portRect.bottom;
newtop := newbottom - PADLENGTH;
end
else
begin
newtop := mouseloc.v;
newbottom := newtop + PADLENGTH;
end;
if (newtop > l_paddle.r.top) then
begin
r.top := l_paddle.r.top;
if newtop > l_paddle.r.bottom then
r.bottom := l_paddle.r.bottom
else
r.bottom := newtop;
end
else if (newtop < l_paddle.r.top) then
begin
r.bottom := l_paddle.r.bottom;
if (newbottom < l_paddle.r.top) then
r.top := l_paddle.r.top
else
r.top := newbottom;
end;
l_paddle.r.top := newtop;
l_paddle.r.bottom := newbottom;
EraseRect(r);
FillRect(l_paddle.r, PAD_PAT);
end
else
FillRect(l_paddle.r, PAD_PAT);
end;
(* someone scored a point *)
procedure kill_ball;
begin
ball.on := false;
volleys := 0;
CopyRgn(ball.Rgn, ball.unRgn);
EraseRgn(ball.Rgn);
recover_from_collision;
blat;
display_score;
end;
(* check for bounces, diRection changes, scoring, etc *)
procedure check_status;
var
ball_r: Rect;
ball_top, ball_bottom, ball_left, ball_right: Integer;
begin
ball_top := ball.Rgn^^.rgnBBox.top;
ball_bottom := ball.Rgn^^.rgnBBox.bottom;
ball_left := ball.Rgn^^.rgnBBox.left;
ball_right := ball.Rgn^^.rgnBBox.right;
ball_r := ball.Rgn^^.rgnBBox;
(* make it a little harder as time goes by *)
if (volleys > 35) then
ball.speed := BALLSPEED + 6
else if (volleys > 30) then
ball.speed := BALLSPEED + 5
else if (volleys > 25) then
ball.speed := BALLSPEED + 4
else if (volleys > 20) then
ball.speed := BALLSPEED + 3
else if (volleys > 15) then
ball.speed := BALLSPEED + 2
else if (volleys > 10) then
ball.speed := BALLSPEED + 1;
r_paddle.speed := ball.speed + 2;
(* the right paddle tries to track the ball *)
if ((ball_right > 250) and (ball.dir = UP_RIGHT) or (ball.dir = DOWN_RIGHT) or (ball.dir = RIGHT)) then
begin
if (ball_top + handicap < r_paddle.r.top) then
r_paddle.dir := UP
else if (ball_bottom - handicap > r_paddle.r.bottom) then
r_paddle.dir := DOWN
else
r_paddle.dir := STOPPED;
end
else
r_paddle.dir := STOPPED;
(* the ball and the left boundry *)
if (ball_left < l_paddle.r.right) then
begin
if (SectRect(ball_r, l_paddle.r, r)) then
begin
volleys := volleys + 1;
bleep;
if (ball_top <= l_paddle.r.top + 15) then
ball.dir := UP_RIGHT
else if (ball_top > l_paddle.r.top + 15) and (ball_bottom < l_paddle.r.top + 30) then
ball.dir := RIGHT
else
ball.dir := DOWN_RIGHT;
end
else
begin
last_won := RIGHT;
r_paddle.score := r_paddle.score + 1;
kill_ball;
end;
Exit(check_status);
end;
(* the ball and the right boundry *)
if (ball_right > r_paddle.r.left) then
begin
if (SectRect(ball_r, r_paddle.r, r)) then
begin
volleys := volleys + 1;
bleep;
if (ball_top <= r_paddle.r.top + 15) then
ball.dir := UP_LEFT
else if (ball_top > r_paddle.r.top + 15) and (ball_bottom < r_paddle.r.top + 30) then
ball.dir := LEFT
else
ball.dir := DOWN_LEFT;
end
else
begin
last_won := LEFT;
l_paddle.score := l_paddle.score + 1;
kill_ball;
end;
Exit(check_status);
end;
(* the ball and the top wall *)
if (ball_top < top_wall.bottom) then
begin
if (ball.dir = UP_LEFT) then
ball.dir := DOWN_LEFT
else if (ball.dir = UP_RIGHT) then
ball.dir := DOWN_RIGHT;
bleep;
Exit(check_status);
end;
(* the ball and the bottom wall *)
if (ball_bottom > bottom_wall.top) then
begin
if (ball.dir = DOWN_LEFT) then
ball.dir := UP_LEFT
else if (ball.dir = DOWN_RIGHT) then
ball.dir := UP_RIGHT;
bleep;
Exit(check_status);
end;
end; {check_status}
procedure Init_game;
begin
l_paddle.score := 0;
r_paddle.score := 0;
ball.speed := BALLSPEED;
kill_ball;
end;
procedure serve_ball;
var
i: Integer;
begin
OffsetRgn(ball.Rgn, 250 - ball.Rgn^^.rgnBBox.right, 150 - (ball.Rgn^^.rgnBBox.top));
for i := 0 to 249 do
begin
check_status;
move_right_paddle;
move_left_paddle;
move_ball;
end;
if last_won = RIGHT then
ball.dir := LEFT
else
ball.dir := RIGHT;
ball.speed := BALLSPEED;
ball.on := true;
PaintRgn(ball.Rgn);
bleep;
end;
procedure create_ball;
begin
ball.Rgn := NewRgn;
ball.oldRgn := NewRgn;
ball.unRgn := NewRgn;
ball.dir := LEFT;
ball.speed := BALLSPEED;
SetRect(r, 250, 150, 250 + BALLWIDTH, 150 + BALLLENGTH);
OpenRgn;
FrameOval(r);
CloseRgn(ball.Rgn);
end;
procedure create_walls;
begin
SetRect(top_wall, winstorage.port.portRect.left + 20, winstorage.port.portRect.top + 5, winstorage.port.portRect.right - 20, winstorage.port.portRect.top + 20);
FillRect(top_wall, WALL_PAT);
SetRect(bottom_wall, winstorage.port.portRect.left + 20, winstorage.port.portRect.bottom - 20, winstorage.port.portRect.right - 20, winstorage.port.portRect.bottom - 5);
FillRect(bottom_wall, WALL_PAT);
end;
procedure create_r_paddle;
begin
r_paddle.dir := STOPPED;
r_paddle.speed := PADDLESPEED;
r_paddle.score := 0;
SetRect(r_paddle.r, winstorage.port.portRect.right - PADWIDTH - PADINSET, winstorage.port.portRect.top + PADINSET, winstorage.port.portRect.right - PADWIDTH - PADINSET + PADWIDTH, winstorage.port.portRect.top + PADINSET + PADLENGTH);
FillRect(r_paddle.r, PAD_PAT);
end;
procedure create_l_paddle;
begin
l_paddle.dir := STOPPED;
l_paddle.speed := PADDLESPEED;
l_paddle.score := 0;
SetRect(l_paddle.r, winstorage.port.portRect.left + PADINSET, winstorage.port.portRect.top + PADINSET, winstorage.port.portRect.left + PADINSET + PADWIDTH, winstorage.port.portRect.top + PADINSET + PADLENGTH);
FillRect(l_paddle.r, PAD_PAT);
end;
procedure DoCommand (menu_selection: LongInt);
var
the_item: Integer;
name: Str255;
begin
the_item := LoWord(menu_selection);
case HiWord(menu_selection) of
appleid:
begin
GetItem(gamemenu[0], the_item, name);
if OpenDeskAcc(name) <> noErr then
;
SetPort(gamewindow);
end;
editid:
if SystemEdit(the_item - 1) then
;
fileid:
case (the_item) of
1:
if (paused) then
begin
paused := false;
SetItem(gamemenu[1], 1, 'Pause');
end
else
begin
paused := true;
SetItem(gamemenu[1], 1, 'Continue');
end;
2:
Init_game;
3:
done := true;
end;
skillid:
begin
CheckItem(gamemenu[3], skill_level, false);
skill_level := the_item;
CheckItem(gamemenu[3], skill_level, true);
end;
soundid:
if sound_on then
begin
sound_on := false;
SetItem(gamemenu[4], 1, 'Sound On');
end
else
begin
sound_on := true;
SetItem(gamemenu[4], 1, 'Sound Off');
end;
end;
HiliteMenu(0);
end;
procedure enable_edit_menu;
begin
EnableItem(gamemenu[2], 1);
EnableItem(gamemenu[2], 3);
EnableItem(gamemenu[2], 4);
EnableItem(gamemenu[2], 5);
EnableItem(gamemenu[2], 6);
end;
procedure disable_edit_menu;
begin
DisableItem(gamemenu[2], 1);
DisableItem(gamemenu[2], 3);
DisableItem(gamemenu[2], 4);
DisableItem(gamemenu[2], 5);
DisableItem(gamemenu[2], 6);
end;
procedure build_menus;
var
i: Integer;
begin
InitMenus;
gamemenu[0] := NewMenu(appleid, '');
gamemenu[1] := NewMenu(fileid, 'File');
gamemenu[2] := NewMenu(editid, 'Edit');
gamemenu[3] := NewMenu(skillid, 'Skill');
gamemenu[4] := NewMenu(soundid, 'Sound');
AppendMenu(gamemenu[0], '(About MacPong…;(-');
AddResMenu(gamemenu[0], 'DRVR');
AppendMenu(gamemenu[1], 'Pause/P;Restart/R;Quit/Q');
AppendMenu(gamemenu[2], '(Undo;(-;(Cut;(Copy;(Paste;(Clear');
AppendMenu(gamemenu[3], 'Beginner;Novice;Normal;Expert');
AppendMenu(gamemenu[4], 'Sound Off/S');
for i := 0 to 4 do
InsertMenu(gamemenu[i], 0);
CheckItem(gamemenu[3], skill_level, true);
DrawMenuBar;
end;
procedure InitSounds;
begin
bleep_buf.mode := swMode;
bleep_buf.triplet[0].count := 1000;
bleep_buf.triplet[0].amplitude := 255;
bleep_buf.triplet[0].duration := 5;
blat_buf.mode := swMode;
blat_buf.triplet[0].count := 1000;
blat_buf.triplet[0].amplitude := 255;
blat_buf.triplet[0].duration := 5;
blat_buf.triplet[1].count := 3000;
blat_buf.triplet[1].amplitude := 255;
blat_buf.triplet[1].duration := 10;
end;
procedure play_pong;
var
startTicks: LongInt;
begin
if not paused and ((l_paddle.score < HIGHSCORE) and (r_paddle.score < HIGHSCORE)) then
begin
startTicks := TickCount;
if (not ball.on) then
serve_ball;
check_status;
move_left_paddle;
move_right_paddle;
move_ball;
while (startTicks = TickCount) do
;
end;
end;
(* pretty much straight from SAMP in I.M. *)
procedure Handle_Events;
var
ch: Char;
mResult: Longint;
theMenu, theItem: Integer;
begin
SystemTask;
{if GetNextEvent(everyEvent, gameEvent) then}
if GetOSEvent(everyEvent, gameEvent) then
begin
case gameEvent.what of
mouseDown:
case FindWindow(gameEvent.where, which_window) of
inMenuBar:
DoCommand(MenuSelect(gameEvent.where));
inSysWindow:
SystemClick(gameEvent, which_window);
inDrag:
DragWindow(which_window, gameEvent.where, dragRect);
inContent:
if (which_window <> FrontWindow) then
SelectWindow(which_window);
end;
keyDown, autoKey:
begin
ch := Char(BAnd(gameEvent.message, charCodeMask));
mResult := MenuKey(ch);
theMenu := HiWord(mResult);
theItem := LoWord(mResult);
if (theMenu <> 0) then
DoCommand(mResult);
end;
updateEvt:
begin
SetPort(gamewindow);
BeginUpdate(gamewindow);
FillRect(l_paddle.r, PAD_PAT);
FillRect(r_paddle.r, PAD_PAT);
FillRect(top_wall, WALL_PAT);
FillRect(bottom_wall, WALL_PAT);
if (ball.on) then
PaintRgn(ball.Rgn);
EndUpdate(gamewindow);
end;
end;
end;
end; { Handle_Events}
procedure setup;
begin
done := false;
skill_level := 2;
sound_on := true;
last_won := RIGHT;
{$IFC UNDEFINED THINK_PASCAL}
InitGraf(thePort);
InitFonts;
InitWindows;
TEInit;
InitDialogs(nil);
InitCursor;
{$ENDC}
InitSounds;
pat_Handle := SysPatternHnd(GetResource('PAT#', 0));
PAD_PAT := pat_Handle^^.pat_list[6];
WALL_PAT := pat_Handle^^.pat_list[10];
title := kTitle;
FlushEvents(everyEvent, 0);
SetRect(r, 4, 40, 508, 338);
SetRect(dragRect, 4, 24, r.right - 4, r.bottom - 4);
gamewindow := NewWindow(@winstorage, r, title, true, 0, WindowPtr(-1), false, 0);
SetPort(gamewindow);
build_menus;
ShowCursor;
create_l_paddle;
create_r_paddle;
create_walls;
create_ball;
Init_game;
end;
{main}
begin
setup;
while (not done) do
begin
Handle_Events;
play_pong;
end;
FlushEvents(everyEvent, 0);
StopSound;
ExitToShell;
end.